﻿using System;
using System.Reflection;
using System.Text;

namespace TypeDescriptor
{
    public static class MethodInfoExtension
    {
        /// <summary>
        /// 返回方法名,为了处理泛型方法
        /// </summary>
        /// <param name="method"></param>
        /// <param name="funcType"></param>
        /// <returns></returns>
        public static string GetMethodName(this MethodInfo method, Func<Type, string> funcType)
        {
            if (method.IsGenericMethod)
            {
                var arguments = method.GetGenericArguments();
                var methodNamSb = new StringBuilder();
                methodNamSb.Append("method.Name<");
                for (int i = 0; i < arguments.Length - 1; i++)
                {
                    methodNamSb.Append(arguments[i].ToString(funcType) + ", ");
                }
                methodNamSb.Append(arguments[arguments.Length - 1]);
                methodNamSb.Append(">");
                return methodNamSb.ToString();
            }
            return method.Name;
        }

        /// <summary>
        /// 返回泛型方法的约束条件
        /// </summary>
        /// <param name="method"></param>
        /// <param name="funcType"></param>
        /// <returns></returns>
        public static string GetMethodConstraint(this MethodInfo method, Func<Type, string> funcType)
        {
            string conStr = "";
            if (method.IsGenericMethod)
            {
                var arguments = method.GetGenericArguments();
                for (int i = 0; i < arguments.Length; i++)
                {
                    var arg = arguments[i];
                    var constraintSb = new StringBuilder();
                    var constraints = arg.GetGenericParameterConstraints();
                    if (constraints.Length > 0)
                    {
                        constraintSb.Append("where ");
                        constraintSb.Append(arg.Name + " : ");
                        for (int j = 0; j < constraints.Length - 1; j++)
                        {
                            constraintSb.Append(constraints[j].ToString(funcType) + ", ");
                        }
                        constraintSb.Append(constraints[constraints.Length - 1].ToString(funcType));

                    }
                    else if (arg.GenericParameterAttributes != GenericParameterAttributes.None)
                    {
                        constraintSb.Append("where ");
                        constraintSb.Append(arg.Name + " : ");
                    }

                    if (arg.GenericParameterAttributes != GenericParameterAttributes.None)
                    {
                        if (!arg.GenericParameterAttributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint) && arg.GenericParameterAttributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
                        {
                            constraintSb.Append("new(), ");
                        }

                        if (arg.GenericParameterAttributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
                        {
                            constraintSb.Append("class, ");
                        }
                    }
                    conStr += CutLastCommaToString(constraintSb) + (i < arguments.Length - 1 ? Environment.NewLine : string.Empty);
                }
            }
            return conStr;
        }

        public static string CutLastCommaToString(StringBuilder sb)
        {
            return sb.ToString().TrimEnd().TrimEnd(',');
        }
    }
}